package it.ap.sa.acqua.auth.controller;

import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import it.ap.sa.acqua.auth.service.UserProfileService;
import it.ap.sa.acqua.auth.service.UserService;
import it.ap.sa.acqua.dao.model.TUser;
import it.ap.sa.acqua.dao.model.TUserProfile;
import it.ap.sa.core.utils.LogUtil;
 
 
 
@Controller
@RequestMapping("/")
@SessionAttributes("roles")
public class AppController {
 
	/**
	 * logger
	 */
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
    @Autowired
    UserService userService;
     
    @Autowired
    UserProfileService userProfileService;
     
    @Autowired
    MessageSource messageSource;
 
    @Autowired
    AuthenticationTrustResolver authenticationTrustResolver;
     
     
    /**
     * This method will list all existing users.
     */
    @RequestMapping(value = { "/" }, method = RequestMethod.GET)
    public String listUsers(ModelMap model) {
 
        List<TUser> users = userService.findAllUsers();
        model.addAttribute("users", users);
        model.addAttribute("loggedinuser", getPrincipal());
        return "userslist";
    }
     
    /**
     * This method will provide UserProfile list to views
     */
    @ModelAttribute("roles")
    public List<TUserProfile> initializeProfiles() {
        return userProfileService.findAll();
    }
     
    /**
     * This method handles Access-Denied redirect.
     */
    @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
    public String accessDeniedPage(ModelMap model) {
        model.addAttribute("loggedinuser", getPrincipal());
        return "accessDenied";
    }
 
    /**
     * This method handles login GET requests.
     * If users is already logged-in and tries to goto login page again, will be redirected to list page.
     */
    @RequestMapping(value = "/login", method = {RequestMethod.POST,RequestMethod.GET})
    public ModelAndView loginPage(
    		@RequestParam(value = "error", required = false) String error, 
    		@RequestParam(value = "logout", required = false) String logout, 
    		@RequestParam(value = "expired", required = false) String expired, 
    		@RequestParam(value = "concurrentSessionExpired", required = false) String concurrentSessionExpired, 
    		@RequestParam(value = "policyLogout", required = false) String policyLogout,
    		HttpServletRequest request, HttpServletResponse response) {
    	
    	ModelAndView model = new ModelAndView();
    	
        if(error != null) {
        	/**
        	 * A standard controller class, refer to the login method, it shows you how to play around with the session value 
        	 * – “SPRING_SECURITY_LAST_EXCEPTION“, and customize the error message.
        	 */
        	Exception exception = (Exception) request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
        	
        	if(exception != null && exception instanceof SessionAuthenticationException) {
        	   /**
				* Thrown by an <tt>SessionAuthenticationStrategy</tt> to indicate that an authentication
				* object is not valid for the current session, typically because the same user has
				* exceeded the number of sessions they are allowed to have concurrently.
        		*/
 	 	       model.addObject("concurrentSessionExpired", "msg concurrentSessionExpired");
 	 	    }
        	else
	           if(exception != null && StringUtils.hasText(exception.getMessage()))
		          /**  **/
		    	  model.addObject("error", exception.getMessage());
//        	else
//        	   /**  **/
//	    	   model.addObject("error", AuthenticationType.LoginCostants.UnidentifiedError.name());
        }
        else
           if(logout != null) 
        	   model.addObject("logout", "msg logout");
        else		
    	   if(expired != null) {
    		   response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    		   model.addObject("expired", "msg expired");
    	   }
    	else
	       if(concurrentSessionExpired != null)
	 	       model.addObject("concurrentSessionExpired", "msg concurrentSessionExpired");
	    else
		   if(policyLogout != null)
		 	   model.addObject("policyLogout", "msg policyLogout");
        
        model.setViewName("login");
        
        return model;
    }
    
    /**
     * This method handles logout requests.
     * Toggle the handlers if you are RememberMe functionality is useless in your app.
     */
    @RequestMapping(value="/accessoNegato", method = RequestMethod.GET)
    public ModelAndView accessoNegatoPage (HttpServletRequest request, HttpServletResponse response){
		String    idLog     = "accessoNegatoPage";
		StopWatch stopWatch = LogUtil.startStopWatch(idLog);
		logger.info("Start " + idLog);
		try{
			ModelAndView  mav      		= new ModelAndView("auth/accessoNeagato");
			mav.addObject("logout", "msg logout");
			return mav;
		}finally{
			logger.info(LogUtil.endStopWatch(stopWatch));
		}
    }
 
    /**
     * This method handles logout requests.
     * Toggle the handlers if you are RememberMe functionality is useless in your app.
     */
    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logoutPage (HttpServletRequest request, HttpServletResponse response){
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){    
            SecurityContextHolder.getContext().setAuthentication(null);
        }
        return "redirect:/login?logout";
    }
 
    /**
     * This method returns the principal[user-name] of logged-in user.
     */
    private String getPrincipal(){
		try{
	    	/**
			 * Recupero i dati dell'utente autenticato 
			 */
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			
			if(authentication != null && authentication.isAuthenticated() && authentication.getPrincipal() instanceof UserDetails) {
				Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
				return ((UserDetails)principal).getUsername();
			} else
			   return null;
		}catch(Exception e){
			logger.error("getPrincipal >>>>>>>>>> " + e, e);
			throw(e);
		}
    }
     
    /**
     * This method returns true if users is already authenticated [logged-in], else false.
     */
    private boolean isCurrentAuthenticationAnonymous() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authenticationTrustResolver.isAnonymous(authentication);
    }
 
 
}
